Skip to main content

cp — Copy Files & Directories Linux coreutils

Copying is one of the most common "safe operations" on a VPS: you duplicate config files before editing, snapshot a WordPress folder before upgrading, or move content into a staging area.
cp (copy) is the standard command for duplicating files and directories—fast, scriptable, and full of safety controls.

When to use cp
  • You want a quick backup copy before making changes
  • You need to duplicate themes, plugins, or uploads for staging
  • You're building automation scripts that assemble folders and files
For large migrations

For large site moves or syncing huge directories repeatedly, prefer rsync — it's more efficient and supports incremental, bandwidth-aware transfers.

Prerequisites

  • Linux VPS (Ubuntu recommended)
  • SSH access with file-level permissions (or sudo)
  • Familiarity with paths (e.g., /var/www/html/wp-content/)

Verify cp is Installed

which cp

Expected output:

/usr/bin/cp

Check version:

cp --version

Expected output:

cp (GNU coreutils) 9.4

Complete Syntax

cp [OPTION]... SOURCE DEST
cp [OPTION]... SOURCE... DIRECTORY
cp [OPTION]... -t DIRECTORY SOURCE...
FormDescription
cp SOURCE DESTCopy a single file to a new name or location
cp SOURCE... DIRECTORYCopy multiple files into a directory
cp -t DIRECTORY SOURCE...Specify the destination first (useful in scripts)
cp -r SOURCE DESTCopy a directory recursively
cp -a SOURCE DESTArchive copy — recursive + preserve all metadata
Key rules
  • SOURCE can be a file, multiple files, or a directory (with -r/-a)
  • DEST must be a directory when copying multiple sources
  • Without -r or -a, directories are silently skipped with an error

Options Reference

OptionMeaningBest For
-rCopy directories recursivelyCopy folders (basic)
-aArchive mode (recursive + preserve all metadata)Backups
-pPreserve mode, ownership, and timestampsConfig backups / migrations
-uCopy only if source is newer than destinationIncremental updates
-iPrompt before overwriteManual safety
-nNever overwrite existing filesAutomation safety
-fForce overwrite without promptingDeploy scripts (use carefully)
-vVerbose: print each file as it is copiedLogs / debugging
-lCreate hard links instead of copyingSave disk space
-sCreate symbolic links instead of copyingQuick aliasing
--parentsPreserve the full source path in destinationStructured backups
--remove-destinationRemove destination file before writingAvoid permission edge cases
--backupMake a backup of each existing destination fileSafe overwrites
--helpShow help and exitQuick reference
--versionShow version and exitCompatibility checks
-a is the safe default for backups

cp -a is equivalent to cp -dR --preserve=all. It copies recursively and preserves all metadata — the best choice for WordPress directory backups.

Quick Decision Table

GoalRecommended Command
Backup a folder reliablycp -a source/ backup/
Copy a folder quickly (no metadata concern)cp -r source/ dest/
Avoid overwriting existing filescp -n source dest
Ask before overwriting (manual work)cp -i source dest
Update only when source is newercp -u source dest
Keep exact folder structure in backupcp --parents path/to/file /backup-root/
Force overwrite in deploy scriptscp -f source dest
Preserve path and avoid permission issuescp --remove-destination source dest

Safety & Automation Patterns

cp -a /var/www/html/wp-content/ /backups/wp-content/

Copies the entire wp-content directory with all permissions, ownership, and timestamps intact.

Best Practices

  • Prefer cp -a for backups — it's recursive and preserves all metadata.
  • Use -n in automation scripts to prevent accidental overwrites silently.
  • Use -i during manual work when you're unsure of the destination state.
  • Use --parents when you want backups that mirror the original path structure.
  • Always verify results with ls -lah to confirm permissions and ownership.
  • Combine -v with -a when debugging backup scripts to trace what was copied.
  • For repeated or large sync operations, switch to rsync instead.
-f overwrites without asking

cp -f destroys the destination silently. Always combine with -v for visibility in scripts, and double-check your target paths.

Troubleshooting

SymptomLikely CauseFix
-r not specified; omitting directorySource is a directory, no -r givenAdd -r or use -a
File overwritten unexpectedlyUsed -f or forgot -i/-nUse -n or -i next time
Wrong permissions after copyMetadata not preservedUse cp -a or cp -p
Permission deniedInsufficient read/write accessUse sudo or fix ownership
Destination file is emptySource is a symlink or zero-byte fileVerify with stat source
Verification commands
# View destination contents and metadata
ls -lah /path/to/dest

# Check a specific file's permissions and owner
ls -l /path/to/dest/file

# Compare timestamps between source and destination
stat source_file dest_file

# Confirm the copy succeeded and nothing was skipped
diff -r source_dir dest_dir

Cheat Sheet

cp file1 file2 # Copy file to a new name
cp file1 file2 /dst/ # Copy multiple files into a folder
cp -r folder/ backup/ # Copy directory recursively
cp -a /var/www/html/wp-content/ /bak/ # Best for backups (archive mode)
cp -i wp-config.php /backups/ # Prompt before overwrite
cp -n style.css themes/ # Skip if destination exists
cp -u new.css themes/ # Copy only if source is newer
cp -v config.php /backups/ # Verbose: show what is being copied
cp --parents a/b/c.txt /backup/ # Preserve full path structure
cp -f index.php /var/www/html/ # Force overwrite
cp -a .htaccess .user.ini /backups/ # Copy dotfiles with metadata
cp -r {plugins,themes} /backups/ # Copy multiple dirs (brace expansion)
cp wp-config.php wp-config-$(date +%Y-%m-%d).bak # Versioned backup

Mini Quiz

  1. Which flag is the best "backup mode" for directories?
  2. What is the difference between cp -r and cp -a?
  3. How do you copy a file only if the source is newer?
  4. Which flag prevents overwriting existing files silently?
  5. What happens if you run cp on a directory without -r or -a?
Answers
  1. -a — it is recursive and preserves all metadata
  2. -r only recurses; -a also preserves permissions, ownership, and timestamps
  3. -u
  4. -n
  5. cp skips the directory and prints: -r not specified; omitting directory

Worked Examples

note

Examples are ordered from basic to advanced so you build understanding progressively before reaching production patterns.

Copy a Single File

cp index.php index.bak.php

Expected output: (silent success)

Copy Multiple Files into a Directory

cp style.css script.js functions.php /var/www/html/wp-content/themes/mytheme/

Expected output: (silent success)

Copy a Directory Without -r (Failure Case)

cp wp-content /backups/

Expected output:

cp: -r not specified; omitting directory 'wp-content'

Copy a Directory Recursively (-r)

cp -r wp-content /backups/

Expected output: (silent success)

Verbose Output (-v)

cp -v index.php index_copy.php

Expected output:

'index.php' -> 'index_copy.php'

Interactive Overwrite Prompt (-i)

cp -i wp-config.php wp-config.php.bak

Expected output (if destination exists):

cp: overwrite 'wp-config.php.bak'?

Copy Only if Newer (-u)

cp -u new-style.css /var/www/html/wp-content/themes/mytheme/

Expected output: (silent success; skips if destination is up-to-date)

Preserve Attributes (-p)

cp -p wp-config.php /backups/

Expected output: (silent success; ownership and timestamps preserved)

cp -a /var/www/html/wp-content /backups/

Expected output: (silent success; full metadata preserved)

No Overwrite (-n)

cp -n style.css /var/www/html/wp-content/themes/mytheme/

Expected output: (silent success; skips if file already exists)

Preserve Full Path (--parents)

cp --parents wp-content/plugins/akismet/akismet.php /backups/

Expected output — resulting path created:

/backups/wp-content/plugins/akismet/akismet.php

Force Overwrite (-f)

cp -f index.php /var/www/html/

Expected output: (silent success)

Risk

This overwrites the destination without prompting. Use only in controlled deploy scripts.

Remove Destination Before Copying (--remove-destination)

cp --remove-destination index.php /var/www/html/

Expected output: (silent success; avoids permission conflicts on immutable files)

Copy All .php Files with Wildcard

cp *.php /var/www/html/wp-content/plugins/custom-plugin/

Expected output: (silent success)

Copy Hidden Files (Dotfiles)

cp -a .htaccess .user.ini /backups/

Expected output: (silent success; dotfiles copied with full metadata)

Copy to Another User's Home (Requires sudo)

sudo cp wp-config.php /home/developer/

Expected output: (silent success)

Copy and Rename in One Command

cp wp-config.php wp-config-2025.php

Expected output: (silent success)

Copy Multiple Directories with Brace Expansion

cp -r {plugins,themes} /backups/

Expected output: (silent success)

Versioned Backup with Date in Filename

cp wp-config.php wp-config-$(date +%Y-%m-%d).bak

Expected output: (silent success; filename includes today's date)

Clone Live Site into Staging

cp -a /var/www/html /var/www/staging/

Expected output: (silent success)

Disk space

Cloning a full WordPress site can be large. Confirm available disk space first with df -h.